﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
public interface ISteeringGear{
	Vector3 SteeringForce {
		set;
	}
}
public interface ISteeringControl{
	void ComputeOppositeForce (List<Transform> others);
}
public class SteeringMgr{
	static List<Transform> steeringObjs = new List<Transform>();
	public static void Add(Transform target){
		if (!steeringObjs.Contains (target))
			steeringObjs.Add (target);
	}
	public static void Remvoe(Transform target){
		if (steeringObjs.Contains (target))
			steeringObjs.Remove (target);
	}
	public static List<Transform> GetSteeringObjs(){
		return steeringObjs;
	}
}

public class SteeringControl : MonoBehaviour,ISteeringControl {
	/// <summary>
	/// 距离对转向角度的权重
	/// </summary>
	public float angleWeigth = 45;
	public float distanceWeigth = 1;
	/// <summary>
	/// 检查范围
	/// </summary>
	public float checkDistancemax = 3;
	public float checkDistancemin = 0.5f;
	/// <summary>
	/// 检查角度
	/// </summary>
	public float checkAngle = 90;
	/// <summary>
	/// 测试使用的
	/// </summary>
	public Transform[] editorOtherObjs;

	/// <summary>
	/// 范围内的点
	/// </summary>
	[HideInInspector]public List<Vector3> computePoint = new List<Vector3>();
	/// <summary>
	/// 反向力
	/// </summary>
	[HideInInspector]public Vector3 OppositeForce;
	void OnEnable(){
		SteeringMgr.Add (transform);
	}
	void OnDisable(){
		SteeringMgr.Remvoe (transform);
	}
	Transform _cachedTransform;
	Transform cachedTransform{
		get{
			if (_cachedTransform == null)
				_cachedTransform = transform;
			return _cachedTransform;
		}
	}
	ISteeringGear steeringGear;
	void Awake(){
		steeringGear = GetComponent<ISteeringGear> ();
	}
	void Update(){
		if(Time.captureFramerate%50 ==0)
		ComputeOppositeForce (SteeringMgr.GetSteeringObjs ());
	}

	void OnDrawGizmos(){
		// Draws a 5 meter long red line in front of the object
		//在物体的前面绘制一个5米长红色的线
		Gizmos.color = Color.red;
		Gizmos.DrawRay (cachedTransform.position, OppositeForce);
		
	}
	public void ComputeOppositeForce(List<Transform> monsters){
		//editorOtherObjs = monsters;
		computePoint.Clear ();
		int max = 0;
		float maxangle = 0;
		for(int i = 0;i<monsters.Count;i++){
			if (CheckIsInRang (monsters[i])) {
				computePoint.Add(ComputeTargetOppositeForce(monsters[i]));
				float a = Vector3.Angle (computePoint [computePoint.Count - 1],cachedTransform.forward);
				if (a>maxangle) {
					maxangle = a;
					max = computePoint.Count - 1;
				}
			}
		}
		if (max >= 0 && max < computePoint.Count) {
			OppositeForce = computePoint [max];
			if (steeringGear != null)
				steeringGear.SteeringForce = OppositeForce;
		} else {
			OppositeForce = Vector3.zero;
			if (steeringGear != null)
				steeringGear.SteeringForce = Vector3.zero;
		}
	}

	#region Compute
	/// <summary>
	/// 检查目标是否在范围内
	/// </summary>
	/// <returns><c>true</c>, if is in rang was checked, <c>false</c> otherwise.</returns>
	/// <param name="target">Target.</param>
	public bool CheckIsInRang(Transform target){
		float dis = Vector3.Distance (target.position, cachedTransform.position);

		if (dis>= checkDistancemin && dis <= checkDistancemax &&
			Vector3.Angle (cachedTransform.forward, target.position - cachedTransform.position) <= checkAngle * 0.5f)
			return true;
		else
			return false;
	}
	/// <summary>
	/// 计算偏移量
	/// </summary>
	/// <returns>The opposite force.</returns>
	/// <param name="Target">Target.</param>
	public Vector3 ComputeTargetOppositeForce(Transform Target){
		Vector3 f = Target.position - cachedTransform.position;
		Quaternion q;
		float dis = checkDistancemax - Vector3.Distance (Target.position, cachedTransform.position);
		if (dis <= 0)
			return Vector3.zero;
		float angle = dis * angleWeigth;
		if(Vector3.Project(f,cachedTransform.right).x<0)
			q = Quaternion.AngleAxis (angle, Vector3.up);
		else
			q = Quaternion.AngleAxis (-angle, Vector3.up);
		f = (q*f).normalized*distanceWeigth*dis;
		//f = f.normalized;
		return f;
	}
	

	#endregion
}
#if UNITY_EDITOR
[CustomEditor (typeof(SteeringControl))]
[CanEditMultipleObjects]
class DrawSolidArc: Editor {
	SteeringControl _target;
	SteeringControl Target{
		get{
			if (_target == null)
				_target = target as SteeringControl;
			return _target;
		}
	}
	void OnSceneGUI () {
		Handles.color =new  Color(1,1,1,0.2f);
		Vector3 forward = Target.transform.forward;
		Quaternion q = Quaternion.AngleAxis (-Target.checkAngle * 0.5f,Target.transform.up);
		forward = q*forward;
		Handles.DrawSolidArc(Target.transform.position,
			Target.transform.up,
			forward,
			Target.checkAngle,
			Target.checkDistancemax);
		Handles.color = Color.white;
		Target.checkDistancemax =
			Handles.ScaleValueHandle(Target.checkDistancemax,
				Target.transform.position + Target.transform.forward*Target.checkDistancemax,
				Target.transform.rotation,
				1,
				Handles.ConeCap,
				1);
		Target.checkAngle =
			Handles.ScaleValueHandle(Target.checkAngle,
				Target.transform.position + Target.transform.forward*Target.checkAngle,
				Target.transform.rotation,
				1,
				Handles.ConeCap,
				1);
			for (int i = 0; i < Target.computePoint.Count; i++) {
				Vector3 other;
				other = Target.computePoint [i];
				Handles.color =  Color.green;
				Handles.DrawSolidArc(other,
				Vector3.up,
					forward,
					360,
					0.4f);
				//Handles.ArrowCap (0, Target.transform.position, Quaternion.AngleAxis (Vector3.Angle (Target.transform.position, Target.OppositeForce [i]), Vector3.up), Target.OppositeForce [i].sqrMagnitude);
				Handles.DrawLine(Target.transform.position,Target.transform.position+Target.computePoint [i]);
			}
			Handles.color = Color.white;
			Handles.DrawLine(Target.transform.position,Target.transform.position+Target.OppositeForce*2);
	}

}
#endif